cmake_minimum_required(VERSION 3.10)
project(topological-hex)

#SET(CMAKE_BUILD_TYPE "Debug")  
#SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g2 -ggdb")  
#SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")  

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

find_package(Doxygen)
find_package(OpenMP)
find_package(PkgConfig)
if(PkgConfig_FOUND)
  pkg_search_module(CHECK check)
endif()

option(BUILD_DOCUMENTATION "Create and install the HTML documentation (requires Doxygen)"
  ${DOXYGEN_FOUND})
option(BUILD_TESTS
  "Compile unit tests used to ensure the API functions correctly (requires Check)"
  ${CHECK_FOUND})
option(COMPUTE_COVERAGE "Generate an HTML report about test coverage (requires lcov)" OFF)
option(ENABLE_SANITIZER "Adds compiler flags to check for undefined behaviors" OFF)

if(BUILD_DOCUMENTATION)
  if(NOT DOXYGEN_FOUND)
    message(FATAL_ERROR "Doxygen is needed to build the documentation.")
  endif()

  set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
  set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)

  configure_file(${doxyfile_in} ${doxyfile} @ONLY)

  add_custom_target(doc
    COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    COMMENT "Generating API documentation with Doxygen"
    VERBATIM)

  install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc)
endif()

if(COMPUTE_COVERAGE)
  include(CodeCoverage)
  APPEND_COVERAGE_COMPILER_FLAGS()
  set(COVERAGE_EXCLUDES '/usr/*' '**/tests/*'
    '**/src/topological_hex.c'
    '**/src/topological_hex-client.c'
    '**/src/topological_hex-server.c'
    '**/src/remesh.c'
    '**/src/MurmurHash3.*')
endif()

if(ENABLE_SANITIZER)
  set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} \
    -fsanitize=undefined -fsanitize=leak -fsanitize=address")
  set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} \
    -fsanitize=undefined -fsanitize=leak -fsanitize=address")
endif()

enable_language(C)

if(OPENMP_FOUND)
  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${OpenMP_EXE_LINKER_FLAGS}")
endif()

set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -g -flto")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -flto")

set(INCLUDE_DIR "${PROJECT_SOURCE_DIR}/src")
include_directories(${INCLUDE_DIR})

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)

set(LIB_SRC
  src/mesh.c src/solver.c src/symmetry.c src/dfs.c src/shellable_dfs.c
  src/queue.c src/parallel_dfs.c
  src/server.c src/protocol.c src/client.c
  src/lower_bound.c src/homology.c src/dual.c src/compatibility.c
  src/errors.c
  src/MurmurHash3.c)

set(TEST_SRC
  tests/runner.c tests/types.c tests/utils.c tests/errors.c tests/vertex_set.c
  tests/sparse_set.c tests/compatibility.c tests/mesh.c tests/solver.c
  tests/lower_bound.c tests/dual.c tests/queue.c
  tests/protocol.c tests/distributed.c)

add_library(topological_hex-lib STATIC ${LIB_SRC})
set_target_properties(topological_hex-lib
  PROPERTIES OUTPUT_NAME topological_hex)
install(TARGETS topological_hex-lib DESTINATION lib)

add_executable(topological_hex src/topological_hex.c)
target_link_libraries(topological_hex topological_hex-lib)

add_executable(topological_hex-client src/topological_hex-client.c)
target_link_libraries(topological_hex-client topological_hex-lib)

add_executable(topological_hex-server src/topological_hex-server.c)
target_link_libraries(topological_hex-server topological_hex-lib)

add_executable(remesh src/remesh.c)
target_link_libraries(remesh topological_hex-lib)

install(TARGETS
  topological_hex
  topological_hex-client
  topological_hex-server
  remesh
  DESTINATION bin)

if (BUILD_TESTS)
  if(NOT CHECK_FOUND)
    message(FATAL_ERROR "Check is needed to build unit tests.")
  endif()

  add_executable(topological_hex-tests ${TEST_SRC})
  target_compile_definitions(topological_hex-tests PUBLIC
    INPUT_DIR="${CMAKE_CURRENT_SOURCE_DIR}/input")
  target_link_libraries(topological_hex-tests topological_hex-lib)
  target_link_libraries(topological_hex-tests ${CHECK_LIBRARIES})

  include(CTest)
  add_test(NAME unit_tests COMMAND topological_hex-tests)
  set_tests_properties(unit_tests PROPERTIES DEPENDS topological_hex-tests)
endif()

if (COMPUTE_COVERAGE)
  SETUP_TARGET_FOR_COVERAGE(
    NAME coverage
    EXECUTABLE topological_hex-tests
    DEPENDENCIES topological_hex-tests)
endif()
